# coding:utf-8
# writingtime: 2020-8-5
# reference: https://doi.org/10.1007/s40815-021-01243-2

from DistanceFunction.euclidean import Euclidean
import numpy as np
from math import exp


class WG:
    def __init__(self, dataList, membershipMatrix, clusterCenter, m=2):
        """
        function
        :param dataList: 样本向量
        :param membershipMatrix: 关系矩阵
        :param clusterCenter: 聚合中心
        :param m: 聚合参数
        """
        self.dataList = dataList
        self.membershipMatrix = membershipMatrix
        self.clusterCenter = clusterCenter
        self.m = m

    def comp(self):
        """
        function: comp部分
        :return:
        """
        sum1 = 0
        for i in range(len(self.clusterCenter)):
            for j in range(len(self.dataList)):
                sum1 += (self.membershipMatrix[i][j] ** 2) * (
                        Euclidean.getresult(self.dataList[j], self.clusterCenter[i]) ** 2)
        return sum1

    def var(self):
        """
        function: var部分
        :return:
        """
        epsilon = 0
        x_mean = np.array([0 for _ in range(self.dataList[0])])
        for i in self.dataList:
            x_mean += np.array(i)
        x_mean = list(x_mean / len(self.dataList))
        for j in self.dataList:
            epsilon += Euclidean.getresult(j, x_mean) ** 2
        epsilon /= len(self.dataList)
        sum1 = 0
        for i in range(len(self.clusterCenter)):
            for j in range(len(self.dataList)):
                sum1 += exp(-(Euclidean.getresult(self.dataList[j], self.clusterCenter[i]) ** 2) / epsilon)
        sum1 /= len(self.dataList)
        return sum1

    def overlap(self):
        """
        function: opverlap部分
        :return:
        """
        li_temp = []
        for i in range(len(self.clusterCenter)):
            for j in range(len(self.clusterCenter)):
                if i != j:
                    sum1 = 0
                    for k in range(len(self.dataList)):
                        sum1 += (1 - abs(self.membershipMatrix[i][k] - self.membershipMatrix[j][k]))
                    li_temp.append(sum1)
        minvalue = min(li_temp)
        return minvalue

    def sim(self):
        """
        function: 计算sim部分
        :return:
        """
        li_temp = []

        for i in range(len(self.clusterCenter)):
            sum1 = 0
            for j in range(len(self.dataList)):
                sum1 += self.membershipMatrix[i][j] ** 2
            li_temp.append(sum1)
        minvalue = min(li_temp)
        return minvalue

    def sep1(self):
        """
        function: 计算sep1部分
        :return:
        """
        li_temp = []
        for i in range(len(self.clusterCenter)):
            for k in range(len(self.clusterCenter)):
                if i != k:
                    li_temp.append(Euclidean.getresult(self.clusterCenter[i], self.clusterCenter[k]) ** 2)
        minvalue = min(li_temp)
        return minvalue

    def sep2(self):
        """
        function: 计算sep2部分
        :return:
        """
        clustermean = np.array([0 for _ in range(len(self.clusterCenter[0]))])
        for i in self.clusterCenter:
            clustermean += np.array(i)
        clustermean = list(clustermean / len(self.clusterCenter))
        sum1 = 0
        for i in self.clusterCenter:
            sum1 += Euclidean.getresult(i, clustermean) ** 2
        sum1 /= len(self.clusterCenter)
        return sum1

    def getwg(self):
        """
        function: 计算wg的最终值
        :return:
        """
        return (self.comp()+self.var()+self.overlap())/(self.sim()+self.sep1()+self.sep2())

    @staticmethod
    def getresult(dataList, membershipMatrix, clusterCenter, m=2, a=2):
        """
        function: wg评价函数
        :param dataList: 样本向量
        :param membershipMatrix: 评价矩阵
        :param clusterCenter: 中心点向量
        :param m: 聚合参数
        :return: wg评价值
        """
        return WG(dataList, membershipMatrix, clusterCenter, m).getwg()

